package cn.jjxx.modules.activiti.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.CustomProperty;
import org.activiti.bpmn.model.ExtensionElement;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.UserTask;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.framework.superutil.j2se.ClassUtil;
import org.framework.superutil.j2se.StackTraceElementUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.jjxx.core.model.AjaxJson;
import cn.jjxx.core.utils.ObjectUtils;
import cn.jjxx.core.utils.SpringContextHolder;
import cn.jjxx.core.utils.StringUtils;
import cn.jjxx.modules.activiti.config.Contacts;
import cn.jjxx.modules.activiti.controller.ActivitiFlowService;
import cn.jjxx.modules.activiti.exception.RepositoryException;
import cn.jjxx.modules.activiti.exception.TaskException;
import cn.jjxx.modules.activiti.extend.ExtProperty;
import cn.jjxx.modules.activiti.extend.graph.HistoryProcessInstanceDiagramCmd;
import cn.jjxx.modules.activiti.service.IFlowService;
import cn.jjxx.modules.activiti.workflow.AssigneeInfo;
import cn.jjxx.modules.activiti.workflow.BillBean;
import cn.jjxx.modules.activiti.workflow.Config;
import cn.jjxx.modules.activiti.workflow.OperateBean;
import cn.jjxx.modules.activiti.workflow.history.HistoryTaskComment;
import cn.jjxx.modules.sys.entity.BillActConfig;
import cn.jjxx.modules.sys.entity.User;
import cn.jjxx.modules.sys.service.IBillActConfigService;
import cn.jjxx.modules.sys.service.IUserService;
import cn.jjxx.modules.sys.utils.UserUtils;
import cn.jjxx.modules.workflow.service.IFlowCommonService;

@Transactional
public class FlowService extends ActivitiService implements IFlowService{

	 @Autowired
	 ProcessEngineConfiguration processEngineConfiguration;
	 @Autowired
	 ProcessEngineFactoryBean processEngine;
	 @Autowired
	 protected IFlowCommonService flowCommonService;
	 @Autowired
	 protected IUserService userService;
	 @Autowired
	 protected IBillActConfigService billActConfigService;
	 
	 private static final String REPEAT_SUBMIT = "重新提交";
	 
	 private static final String HIT_REQUISITE = "policy==1";//打回条件代码
	
	/**
	 * @Description: 部署流程 .<br>
	 * @param file zip格式的文件.<br>
	 * @param filename 部署流程的名称.<br>
	 * @return boolean 返回是否部署成功.<br> 
	 * @author 郑成功 .<br>
	 * @throws RepositoryException 
	 * @date 2017-9-19 下午3:24:23.<br>
	 */
	@Override
	public boolean saveNewDeployeFile(File file, String filename) throws RepositoryException {
		try {
			//2：将File类型的文件转化成ZipInputStream流
			ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(file));
			//创建部署对象
			DeploymentBuilder builder = repositoryService.createDeployment();
			//添加部署名称和部署文件，并完成部署
			builder.name(filename).addZipInputStream(zipInputStream).deploy();
			return true;
		} catch (Exception e) {			
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.部署异常.toString(), className, e);
			throw new RepositoryException(message,e);
		}		
	}
	
	
	/**
	 * @Description: 部署流程.<br>
	 * @param in 通过输入流的方式 .<br>
	 * @param filename 部署流程的名称 .<br>
	 * @return boolean .<br> 
	 * @author 郑成功 .<br>
	 * @throws RepositoryException 
	 * @date 2017-9-19 下午3:25:14.<br>
	 */
	@Override
	public boolean saveNewDeployInputStream(InputStream in,String filename) throws RepositoryException{
		try {			
			//2：将File类型的文件转化成ZipInputStream流
			ZipInputStream zipInputStream = new ZipInputStream(in);
			//创建部署对象
			DeploymentBuilder builder = repositoryService.createDeployment();
			//添加部署名称和部署文件，并完成部署
			builder.name(filename).addZipInputStream(zipInputStream).deploy();
			return true;
		} catch (Exception e) {	
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.部署异常.toString(), className, e);
			throw new RepositoryException(message,e);
		}
	}
	
	/**
	 * @Description: 提交流程，返回是否提交成功 .<br>
	 * @param billBean 单据的相关信息.<br>
	 * @param assignees 处理人信息.<br>
	 * @param isAutoSubmit 是否自动处理下一步审批 .<br>
	 * @return boolean 是否提交成功 .<br> 
	 * @param billInfo 单据信息，用来走流程条件的信息.<br>
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2017-9-21 上午9:22:01.<br>
	 */
	@Deprecated
	@Override
	public boolean submitFlow(BillBean billBean, AssigneeInfo assignees, boolean isAutoHandle, Map<String,Object> billInfo) throws TaskException {
		try {
			Map<String,Object> variable = new HashMap<String, Object>();
			String submitUser = assignees.getAssigneeId();
			variable.put(Config.constant.submitUser.toString(), submitUser);
			identityService.setAuthenticatedUserId(submitUser);
			ProcessInstance pi = runtimeService.startProcessInstanceByKey(billBean.getKey(),billBean.getBillId(),variable);			
			if(pi!=null){
				String proInstId = pi.getProcessInstanceId();
				runtimeService.setVariable(proInstId, Config.variable.表单信息.toString(), billBean);
				if(isAutoHandle){
					String assignee = submitUser;
			    	while(findUserTaskByProInst(assignee, proInstId)!=null){
			    		if(billInfo==null||billInfo.size()==0){
			    			taskService.complete(findUserTaskByProInst(assignee, proInstId).getId());
			    		}else{
			    			taskService.complete(findUserTaskByProInst(assignee, proInstId).getId(),billInfo);
			    		}
			    	}
				}
		    	return true;
			}
			return false;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.提交异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}
	
	@Override
	public boolean submitFlow(BillBean billBean,boolean isAutoSubmit) throws TaskException {
		User user = UserUtils.getUser();
		AssigneeInfo assigneeInfo = new AssigneeInfo();
		//如果单据还在流程中，提交将执行审批，否则执行提交操作
		HistoricProcessInstance proInst = historyService.createHistoricProcessInstanceQuery()
				.processInstanceBusinessKey(billBean.getBillId())
				.unfinished().singleResult();
		String taskId = getTaskId(billBean.getBillId());
		try {
			//查询单据信息
			String billId = billBean.getBillId();
			String idFeild = billBean.getIdFeild();
			String statusFeild = billBean.getStatusFeild();
			int status = Contacts.SUBMIT;
			if(proInst==null){
				assigneeInfo.setAssigneeId(user.getId());
				assigneeInfo.setAssigneeName(user.getRealname());
				billBean.setSubmitter(user.getId());
				billBean.setSubmitName(user.getRealname());
				Map<String,Object> billInfo = new HashMap<String, Object>();
				if(StringUtils.isNotEmpty(billBean.getCustomSql())){
					billInfo = flowCommonService.findCustomSql(billBean.getCustomSql());
				}else{
					billInfo = flowCommonService.findBillInfo(billId, billBean.getTableName(), idFeild);
				}
				Map<String,Object> variable = new HashMap<String, Object>();
				String submitUser = assigneeInfo.getAssigneeId();
				variable.put(Config.constant.submitUser.toString(), submitUser);
				variable.put(Config.variable.表单信息.toString(), billBean);
				variable.putAll(billInfo);
				identityService.setAuthenticatedUserId(submitUser);
				ProcessInstance pi = runtimeService.startProcessInstanceByKey(billBean.getKey(),billBean.getBillId(),variable);			
				if(pi!=null){
					String proInstId = pi.getProcessInstanceId();
					//runtimeService.setVariable(proInstId, Config.variable.表单信息.toString(), billBean);
					//修改单据状态
					boolean updateStatus = flowCommonService.updateBillStatus(billId, billBean.getTableName(), idFeild, statusFeild, status);
					if(updateStatus&&isAutoSubmit){
						String assignee = submitUser;
				    	while(findUserTaskByProInst(assignee, proInstId)!=null){
				    		if(billInfo==null||billInfo.size()==0){
				    			String newTaskId = findUserTaskByProInst(assignee, proInstId).getId();
				    			taskService.addComment(newTaskId, proInstId, (new OperateBean()).getOpinion());
				    			taskService.complete(newTaskId);
				    		}else{
				    			String newTaskId = findUserTaskByProInst(assignee, proInstId).getId();
				    			billInfo.put(Config.constant.policy.toString(), (new OperateBean()).getPolicy());
				    			billInfo.put(Config.constant.customAuditor.toString(), submitUser);
				    			taskService.addComment(newTaskId, proInstId, (new OperateBean()).getOpinion());
				    			taskService.complete(newTaskId,billInfo);
				    		}
				    	}
					}
				}
			}else{
				if(taskId!=null){
					OperateBean operate = new OperateBean();
					operate.setOpinion(REPEAT_SUBMIT);
					//完成之前必须获取单据信息
					Map<String,Object> billInfo = flowService.getBillInfo(billBean);
					completeTask(taskId, operate, assigneeInfo, isAutoSubmit, billInfo);
					flowCommonService.updateBillStatus(billId, billBean.getTableName(), idFeild, statusFeild, status);
				}else{
					return false;
				}
			}
			//获取流程下一步处理人或者待处理人，发送短信
			flowService.sendSms(billBean.getBillId());
			//是否需要回调
			flowService.callFlowClass(billBean,Contacts.SUBMIT_FLOW_TYPE, billBean.getBillId());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.提交异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}
	
	/**
	 * @Description: 根据单据Id,获取单据在流程中的任务Id .<br>
	 * @param billId 单据Id.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-11-26 下午5:03:33.<br>
	 */
	private String getTaskId(String billId){
		HistoricProcessInstance proInst = historyService.createHistoricProcessInstanceQuery()
				.processInstanceBusinessKey(billId)
				.unfinished().singleResult();
		if(proInst!=null){
			Task task = taskService.createTaskQuery()
					.processInstanceId(proInst.getId())
					.taskAssignee(UserUtils.getUser().getId())
					.singleResult();
			
			return !ObjectUtils.isNullOrEmpty(task)?task.getId():null;
		}
		return null;
	}

	/**
	 * @Description: 审批流程,判断是否审批成功 .<br>
	 * @param taskId 当前任务Id.<br>
	 * @param operate 处理人(当前登录人或其他处理人信息).<br>
	 * @param assignees 处理人信息.<br>
	 * @param isAutoHandle 是否自动处理下一步审批（相同的人） .<br>
	 * @param billInfo 单据信息，用来走流程条件的信息.<br>
	 * @return boolean .<br> 
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2017-9-21 上午9:30:00.<br>
	 */
	@Override
	public boolean completeTask(String taskId, OperateBean operate, AssigneeInfo assignees, 
			boolean isAutoHandle, Map<String,Object> billInfo) throws TaskException {
		try {
			Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			String executionId = task.getExecutionId();
			String proInstId = task.getProcessInstanceId();
			BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
			//根据单据信息的相关条件，判断流程的走向
			billInfo.put(Config.constant.policy.toString(), operate.getPolicy());
			billInfo.put(Config.constant.customAuditor.toString(), operate.getCustomAuditor());
			//添加审批批注
			taskService.addComment(taskId, proInstId, String.valueOf(operate.getPolicy()), operate.getOpinion());
			//根据条件完成任务
			taskService.complete(taskId, billInfo);
			//是否自动处理
			if(isAutoHandle){
				String assignee = assignees.getAssigneeId();
		    	while(findUserTaskByProInst(assignee, proInstId)!=null){
		    		if(billInfo==null||billInfo.size()==0){
		    			String newTaskId = findUserTaskByProInst(assignee, proInstId).getId();
		    			taskService.addComment(newTaskId, proInstId, (new OperateBean()).getOpinion());
		    			taskService.complete(newTaskId);
		    		}else{
		    			String newTaskId = findUserTaskByProInst(assignee, proInstId).getId();
		    			billInfo.put(Config.constant.policy.toString(), (new OperateBean()).getPolicy());
		    			billInfo.put(Config.constant.customAuditor.toString(), operate.getCustomAuditor());
		    			taskService.addComment(newTaskId, proInstId, (new OperateBean()).getOpinion());
		    			taskService.complete(findUserTaskByProInst(assignee, proInstId).getId(),billInfo);
		    		}
		    	}
			}
			updateBill(task,billBean);
			//是否需要回调
			callFlowClass(billBean,Contacts.COMPLETE_FLOW_TYPE, billBean.getBillId());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.审批异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	} 
	
	/**
	 * @Description: 驳回流程 .<br>
	 * @param taskId 当前任务ID .<br>
	 * @param activityId 驳回节点ID .<br>
	 * @param variables 流程存储参数 .<br>
	 * @return boolean 是否驳回成功.<br> 
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2017-9-21 上午11:23:40.<br>
	 */
	@Override
	public boolean backProcess(String taskId, String activityId, Map<String, Object> variables,String reason) throws TaskException {
		if (activityId==null) {  
            return false;
        } 
		try {
			//通过taskId,获取流程实例
	        ProcessInstance pi = findProcessInstanceByTaskId(taskId);
	        //通过taskId，获取任务
	        TaskEntity taskEntity = findTaskById(taskId);
	        BillBean billBean = runtimeService.getVariable(taskEntity.getExecutionId(), Config.variable.表单信息.toString(), BillBean.class);
	        // 查询本节点发起的会签任务，并结束  
	        List<Task> tasks = taskService.createTaskQuery().processInstanceId(pi.getId())  
	                .taskDescription(Config.activiNodeType.jointProcess.toString()).list(); 
	        //清除不是当前节点的其他会签信息
	        for(Task t:tasks){
	        	if(t.getParentTaskId()==null||!t.getParentTaskId().equals(taskId)){
	        		tasks.remove(t);
	        	}
	        }
	        for (Task task : tasks) {  
	            commitProcess(task.getId(), null, null);  
	        }  
	        // 查找所有并行任务节点，同时驳回  
	        List<Task> taskList = findTaskListByKey(pi.getId(), taskEntity.getTaskDefinitionKey());  
	        for (Task task : taskList) {  
	            commitProcess(task.getId(), variables, activityId);  
	        }  
	        callFlowClass(billBean,Contacts.BACK_FLOW_TYPE, billBean.getBillId());
	        return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.驳回异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}  
    
    /**
	 * @Description: 会签操作 .<br>
	 * @param taskId 任务Id .<br>
	 * @param assignees 会签人账号集合 .<br>
	 * @return boolean 是否会签成功 .<br> 
	 * @author 郑成功 .<br>
     * @throws TaskException 
	 * @date 2017-9-19 下午4:34:22.<br>
	 */
    public boolean jointProcess(String taskId, List<AssigneeInfo> assignees) throws TaskException {
    	TaskEntity taskInfo = findTaskById(taskId);
		String executionId = taskInfo.getExecutionId();
		BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
        for (AssigneeInfo assignee : assignees) {  
            TaskEntity task = (TaskEntity) taskService.newTask(null);  
            task.setAssignee(assignee.getAssigneeId());  
            task.setName(taskInfo.getName() + Config.JOIN_PROCESS);  
            task.setProcessDefinitionId(findProcessDefinitionEntityByTaskId(taskId).getId());  
            task.setProcessInstanceId(findProcessInstanceByTaskId(taskId).getId());  
            task.setParentTaskId(taskId);  
            task.setDescription(Config.activiNodeType.jointProcess.toString());  
            task.setExecutionId(taskInfo.getExecutionId());
            taskService.saveTask(task);  
        }
        //是否需要回调
		callFlowClass(billBean,Contacts.TRANS_FLOW_TYPE, billBean.getBillId());
        return true;
    } 
    
    /**
     * @Description: 转办流程  .<br>
     * @param taskId 当前任务节点ID .<br>
     * @param assignee 被转办人.<br>   
     * @return boolean 是否转办成功 .<br> 
     * @author 郑成功 .<br>
     * @throws TaskException 
     * @date 2017-9-19 下午4:06:58.<br>
     */
    public boolean transferAssignee(String taskId, String assignee,String reason) throws TaskException {
    	try {
    		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			String executionId = task.getExecutionId();
			
    		taskService.setAssignee(taskId, assignee); 
    		BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
    		flowService.sendSms(billBean.getBillId());
    		//是否需要回调
			callFlowClass(billBean,Contacts.TRANS_FLOW_TYPE, billBean.getBillId());
    		return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.转办异常.toString(), className, e);
			throw new TaskException(message,e);
		}
    }

    /**
	 * @Description: 根据当前任务ID，查询可以驳回的任务节点  .<br>
	 * @param @param taskId 当前任务Id.<br>
	 * @return List<ActivityImpl> 可以驳回的任务节点集合.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-20 下午5:36:14.<br>
	 */
	@Override
	public List<ActivityImpl> findBackAvtivity(String taskId) {
		List<ActivityImpl> rtnList = null;  
		if (isJointTask(taskId)) {// 会签任务节点，不允许驳回  
            rtnList = new ArrayList<ActivityImpl>();  
        } else { 
        	try {
        		rtnList = iteratorBackActivity(taskId, findActivitiImpl(taskId,  
                        null), new ArrayList<ActivityImpl>(),  
                        new ArrayList<ActivityImpl>());  
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
        }  
        return reverList(rtnList);  
	}
	
	/**
	 * @Description: 检测是否是会签任务 .<br>
	 * @param taskId 任务Id.<br>
	 * @return boolean 是否是会签任务.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 上午10:56:41.<br>
	 */
	private boolean isJointTask(String taskId){
		//TODO 检测是否是会签任务
		return false;
	}
	/**
	 * @Description: 任务节点排序 .<br>
	 * @param list 所有活动节点.<br>
	 * @param flowElements 所有流程节点.<br>
	 * @param isAsc 是否正序排列.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-5-27 下午12:28:33.<br>
	 */
	private List<ActivityImpl> sortActivityImpl(List<ActivityImpl> list,List<FlowElement> flowElements,boolean isAsc){
		List<ActivityImpl> rtnList = new ArrayList<ActivityImpl>();  
		for(FlowElement fe:flowElements){
			for(ActivityImpl acti:list){
				if(fe.getId().equals(acti.getId())){
					rtnList.add(acti);
				}
			}
		}
		return rtnList;
	}
	
	/** 
     * 反向排序list集合，便于驳回节点按顺序显示 
     *  
     * @param list 
     * @return 
     */  
    private List<ActivityImpl> reverList(List<ActivityImpl> list) {  
        List<ActivityImpl> rtnList = new ArrayList<ActivityImpl>();  
        // 由于迭代出现重复数据，排除重复  
        for (int i = list.size(); i > 0; i--) {  
            if (!rtnList.contains(list.get(i - 1)))  
                rtnList.add(list.get(i - 1));  
        }  
        return rtnList;  
    }  

	/**
	 * @Description: 根据流程实例Id,挂起流程 .<br>
	 * @param processInstanceId 流程实例Id .<br>
	 * @return boolean 是否挂起.<br> 
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2017-9-19 下午4:20:04.<br>
	 */
	@Override
	public boolean suspendProcessInstance(String processInstanceId,String taskId) throws TaskException {
		try {
			Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			String executionId = task.getExecutionId();
			BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
			//挂起流程
			runtimeService.suspendProcessInstanceById(processInstanceId);
			callFlowClass(billBean,Contacts.SUSPEND_FLOW_TYPE, billBean.getBillId());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.挂起异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}

	/**
	 * @Description: 根据流程实例Id,激活流程 .<br>
	 * @param taskId 流程实例Id .<br>
	 * @return boolean 是否激活 .<br> 
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2017-9-19 下午4:19:37.<br>
	 */
	@Override
	public boolean activateProcessInstance(String processInstanceId,String taskId) throws TaskException {
		try {
			Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			String executionId = task.getExecutionId();
			BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
			//通过任务Id,获取流程实例Id
			ProcessInstance pi = flowService.findProcessInstanceByTaskId(taskId);
			runtimeService.activateProcessInstanceById(processInstanceId);
			//是否需要回调
			callFlowClass(billBean,Contacts.ACTIVATE_FLOW_TYPE, billBean.getBillId());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.激活异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}

	/**
	 * @Description: 根据任务Id,终止流程 .<br>
	 * @param taskId 当前任务Id.<br>
	 * @return boolean 是否终止 .<br> 
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2017-9-19 下午4:31:48.<br>
	 */
	@Override
	public boolean endProcess(String taskId) throws TaskException {
		try {
			TaskEntity task = flowService.findTaskById(taskId);
			BillBean billBean = runtimeService.getVariable(task.getExecutionId(), Config.variable.表单信息.toString(), BillBean.class);
			//查询单据信息
			String billId = billBean.getBillId();
			String tableName = billBean.getTableName();
			String idFeild = billBean.getIdFeild();
			String statusFeild = billBean.getStatusFeild();
			int status = Contacts.SAVE;
			ProcessInstance proInst = findProcessInstanceByTaskId(taskId);
			runtimeService.deleteProcessInstance(proInst.getId(), Contacts.flowCloseStatus.closed.toString());
			//更新单据状态
			flowCommonService.updateBillStatus(billId, tableName, idFeild, statusFeild, status);
			//执行回调函数
			callFlowClass(billBean,Contacts.CLOSED_FLOW_TYPE, billBean.getBillId());
			return true;
		} catch (Exception e) {
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.终止异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	} 
	
	/**
	 * @Description: 通过任务Id,获取流程定义 .<br>
	 * @param @param taskId 任务Id.<br>
	 * @return TaskEntity task任务实体.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-19 下午5:20:51.<br>
	 */
	@Override
	public TaskEntity findTaskById(String taskId) {
		try {
			TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();  
	        return task; 
		} catch (Exception e) {
			return null; 
		}
	} 
	
	@Override
	public HistoricTaskInstance findHisTaskById(String taskId){
		return historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
	}
	
	/**
	 * @Description: 通过任务Id,获取流程定义实体 .<br>
	 * @param @param taskId 任务Id.<br>
	 * @return ProcessDefinitionEntity 流程定义实体.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-19 下午5:21:25.<br>
	 */
	@Override
	public ProcessDefinitionEntity findProcessDefinitionEntityByTaskId(String taskId) {  
		try {
			String processDefinitionId = findTaskById(taskId).getProcessDefinitionId();
			if(processDefinitionId!=null){
				RepositoryServiceImpl repositoryServiceImpl = (RepositoryServiceImpl) repositoryService;
				ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity)repositoryServiceImpl
						.getDeployedProcessDefinition(processDefinitionId); 
				return processDefinition;
			}else{
				return null;
			}
		} catch (Exception e) {
			return null;  
		}
    }

	/**
	 * @Description: 根据任务ID和节点ID获取活动节点 .<br>
	 * @param taskId 任务Id .<br>
	 * @param activityId 活动节点Id .<br>
	 * @return ActivityImpl 活动节点信息.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-20 下午5:28:00.<br>
	 */
	@Override
	public ActivityImpl findActivitiImpl(String taskId, String activityId) {
		// 取得流程定义  
        ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityByTaskId(taskId);  
        // 获取当前活动节点ID  
        if (activityId==null) {  
            activityId = findTaskById(taskId).getTaskDefinitionKey();  
        }  
        // 根据流程定义，获取该流程实例的结束节点  
        if (activityId.toLowerCase().equals(Config.activiNodeType.end.toString())) {  
            for (ActivityImpl activityImpl : processDefinition.getActivities()) {  
                List<PvmTransition> pvmTransitionList = activityImpl.getOutgoingTransitions();  
                if (pvmTransitionList.isEmpty()) {  
                    return activityImpl;  
                }  
            }  
        }  
        // 根据节点ID，获取对应的活动节点  
        ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition).findActivity(activityId);  
        return activityImpl;  
	}
	
	/**
     * @Description: el表达式判断 .<br>
     * @param key 判断的key .<br>
     * @param el el表达式  .<br>
     * @param value 判断的值 .<br>
     * @return boolean .<br> 
     * @author 郑成功 .<br>
     * @date 2017-9-20 上午11:28:11.<br>
     */
	private void commitProcess(String taskId, Map<String, Object> variables,String activityId) throws Exception {  
        if (variables == null) {  
            variables = new HashMap<String, Object>();  
        }  
        // 跳转节点为空，默认提交操作  
        if (activityId==null) {  
            taskService.complete(taskId, variables);  
        } else {// 流程转向操作  
            turnTransition(taskId, activityId, variables);  
        }  
    } 
	
	/**
	 * @Description: 流程转向操作 .<br>
	 * @param taskId 当前任务ID .<br>
	 * @param activityId 目标节点任务ID .<br>
	 * @param variables 流程变量  .<br>
	 * @throws Exception 抛出错误异常.<br>   
	 * @return void .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 上午10:14:03.<br>
	 */
    private void turnTransition(String taskId, String activityId,  
            Map<String, Object> variables) throws Exception {  
        // 当前节点  
        ActivityImpl currActivity = findActivitiImpl(taskId, null);  
        // 清空当前流向  
        List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);  
  
        // 创建新流向  
        TransitionImpl newTransition = currActivity.createOutgoingTransition();  
        // 目标节点  
        ActivityImpl pointActivity = findActivitiImpl(taskId, activityId);  
        // 设置新流向的目标节点  
        newTransition.setDestination(pointActivity);  
  
        // 执行转向任务  
        taskService.complete(taskId, variables);  
        // 删除目标节点新流入  
        pointActivity.getIncomingTransitions().remove(newTransition);  
  
        // 还原以前流向  
        restoreTransition(currActivity, oriPvmTransitionList);  
    } 
  
    /**
     * @Description: 清空指定活动节点流向  .<br>
     * @param @param activityImpl 活动节点 .<br>
     * @return List<PvmTransition> 节点流向集合 .<br> 
     * @author 郑成功 .<br>
     * @date 2017-9-21 上午10:15:37.<br>
     */
    private List<PvmTransition> clearTransition(ActivityImpl activityImpl) {  
        // 存储当前节点所有流向临时变量  
        List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();  
        // 获取当前节点所有流向，存储到临时变量，然后清空  
        List<PvmTransition> pvmTransitionList = activityImpl  
                .getOutgoingTransitions();  
        for (PvmTransition pvmTransition : pvmTransitionList) {  
            oriPvmTransitionList.add(pvmTransition);  
        }  
        pvmTransitionList.clear();  
  
        return oriPvmTransitionList;  
    }
    
    /**
     * @Description: 还原指定活动节点流向  .<br>
     * @param @param activityImpl 活动节点  .<br>
     * @param @param oriPvmTransitionList 原有节点流向集合  .<br>   
     * @author 郑成功 .<br>
     * @date 2017-9-21 上午10:16:30.<br>
     */
    private void restoreTransition(ActivityImpl activityImpl,  
            List<PvmTransition> oriPvmTransitionList) {  
        // 清空现有流向  
        List<PvmTransition> pvmTransitionList = activityImpl  
                .getOutgoingTransitions();  
        pvmTransitionList.clear();  
        // 还原以前流向  
        for (PvmTransition pvmTransition : oriPvmTransitionList) {  
            pvmTransitionList.add(pvmTransition);  
        }  
    }
    
    /**
     * @Description: el表达式判断 .<br>
     * @param key 判断的key .<br>
     * @param el el表达式  .<br>
     * @param value 判断的值 .<br>
     * @return boolean .<br> 
     * @author 郑成功 .<br>
     * @date 2017-9-20 上午11:28:11.<br>
     */
    public boolean isCondition(String key, String el, String value) {  
        ExpressionFactory factory = new ExpressionFactoryImpl();    
        SimpleContext context = new SimpleContext();    
        context.setVariable(key, factory.createValueExpression(value, String.class));    
        ValueExpression e = factory.createValueExpression(context, el, boolean.class);    
        return (Boolean) e.getValue(context);  
    }


    /**
	 * @Description: 根据流程实例Id和处理人，查询正在运行的任务 .<br>
	 * @param assignee 处理人 .<br>
	 * @param processInstanceId 流程实例Id .<br>
	 * @return Task 返回代办任务信息.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 上午8:30:53.<br>
	 */
	@Override
	public Task findUserTaskByProInst(String assignee, String processInstanceId) {
		try {
			Task task = taskService.createTaskQuery().taskAssignee(assignee)
					 .processInstanceId(processInstanceId).singleResult();
			return task;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/** 
     * 迭代循环流程树结构，查询当前节点可驳回的任务节点 
     *  
     * @param taskId 
     *            当前任务ID 
     * @param currActivity 
     *            当前活动节点 
     * @param rtnList 
     *            存储回退节点集合 
     * @param tempList 
     *            临时存储节点集合（存储一次迭代过程中的同级userTask节点） 
     * @return 回退节点集合 
     */  
    private List<ActivityImpl> iteratorBackActivity(String taskId,  
            ActivityImpl currActivity, List<ActivityImpl> rtnList,  
            List<ActivityImpl> tempList) throws Exception {  
        // 查询流程定义，生成流程树结构  
        ProcessInstance processInstance = findProcessInstanceByTaskId(taskId);  
  
        // 当前节点的流入来源  
        List<PvmTransition> incomingTransitions = currActivity  
                .getIncomingTransitions();  
        // 条件分支节点集合，userTask节点遍历完毕，迭代遍历此集合，查询条件分支对应的userTask节点  
        List<ActivityImpl> exclusiveGateways = new ArrayList<ActivityImpl>();  
        // 并行节点集合，userTask节点遍历完毕，迭代遍历此集合，查询并行节点对应的userTask节点  
        List<ActivityImpl> parallelGateways = new ArrayList<ActivityImpl>();  
        // 遍历当前节点所有流入路径  
        for (PvmTransition pvmTransition : incomingTransitions) {  
            TransitionImpl transitionImpl = (TransitionImpl) pvmTransition;  
            ActivityImpl activityImpl = transitionImpl.getSource();  
            String type = (String) activityImpl.getProperty(Config.constant.type.toString());  
            /** 
             * 并行节点配置要求：<br> 
             * 必须成对出现，且要求分别配置节点ID为:XXX_start(开始)，XXX_end(结束) 
             */  
            if (Config.activiNodeType.parallelGateway.toString().equals(type)) {// 并行路线  
                String gatewayId = activityImpl.getId();  
                String gatewayType = gatewayId.substring(gatewayId.lastIndexOf("_") + 1);  
                if (Config.activiNodeType.start.toString().equals(gatewayType.toLowerCase())) {// 并行起点，停止递归  
                    return rtnList;  
                } else {// 并行终点，临时存储此节点，本次循环结束，迭代集合，查询对应的userTask节点  
                    parallelGateways.add(activityImpl);  
                }  
            } else if (Config.activiNodeType.startEvent.toString().equals(type)) {// 开始节点，停止递归  
                return rtnList;  
            } else if (Config.activiNodeType.userTask.toString().equals(type)) {// 用户任务  
                tempList.add(activityImpl);  
            } else if (Config.activiNodeType.exclusiveGateway.toString().equals(type)) {// 分支路线，临时存储此节点，本次循环结束，迭代集合，查询对应的userTask节点  
                currActivity = transitionImpl.getSource();  
                exclusiveGateways.add(currActivity);  
            }  
        }  
  
        /** 
         * 迭代条件分支集合，查询对应的userTask节点 
         */  
        for (ActivityImpl activityImpl : exclusiveGateways) {  
            iteratorBackActivity(taskId, activityImpl, rtnList, tempList);  
        }  
  
        /** 
         * 迭代并行集合，查询对应的userTask节点 
         */  
        for (ActivityImpl activityImpl : parallelGateways) {  
            iteratorBackActivity(taskId, activityImpl, rtnList, tempList);  
        }  
  
        /** 
         * 根据同级userTask集合，过滤最近发生的节点 
         */  
        currActivity = filterNewestActivity(processInstance, tempList);  
        if (currActivity != null) {  
            // 查询当前节点的流向是否为并行终点，并获取并行起点ID  
            String id = findParallelGatewayId(currActivity);  
            if (id==null) {// 并行起点ID为空，此节点流向不是并行终点，符合驳回条件，存储此节点  
                rtnList.add(currActivity);  
            } else {// 根据并行起点ID查询当前节点，然后迭代查询其对应的userTask任务节点  
                currActivity = findActivitiImpl(taskId, id);  
            }  
  
            // 清空本次迭代临时集合  
            tempList.clear();  
            // 执行下次迭代  
            iteratorBackActivity(taskId, currActivity, rtnList, tempList);  
        }  
        return rtnList;  
    }  
	
	/**
	 * @Description: 通过任务Id,获取流程实例 .<br>
	 * @param taskId 任务Id .<br>
	 * @return ProcessInstance 返回流程实例 .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 上午11:11:21.<br>
	 */
	@Override
	public ProcessInstance findProcessInstanceByTaskId(String taskId) {
		try {
			String proInstId = findTaskById(taskId).getProcessInstanceId();
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(proInstId).singleResult(); 
			return processInstance;  
		} catch (Exception e) {
			return null;
		}
	}
	
	@Override
	public HistoricProcessInstance findHisProcessInstanceByTaskId(String taskId) {
		try {
			HistoricTaskInstance task = findHisTaskById(taskId);
			String proInstId = task!=null?task.getProcessInstanceId():taskId;
			HistoricProcessInstance hisProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(proInstId).singleResult(); 
			return hisProcessInstance;  
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * @Description: 根据流入任务集合，查询最近一次的流入任务节点  .<br>
	 * @param processInstance 流程实例   .<br>
	 * @param tempList 流入任务集合  .<br>
	 * @return ActivityImpl .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 上午11:16:02.<br>
	 */
    private ActivityImpl filterNewestActivity(ProcessInstance processInstance,  
            List<ActivityImpl> tempList) {  
        while (tempList.size() > 0) {  
            ActivityImpl activity_1 = tempList.get(0);  
            HistoricActivityInstance activityInstance_1 = findHistoricUserTask(  
                    processInstance, activity_1.getId());  
            if (activityInstance_1 == null) {  
                tempList.remove(activity_1);  
                continue;  
            }  
  
            if (tempList.size() > 1) {  
                ActivityImpl activity_2 = tempList.get(1);  
                HistoricActivityInstance activityInstance_2 = findHistoricUserTask(  
                        processInstance, activity_2.getId());  
                if (activityInstance_2 == null) {  
                    tempList.remove(activity_2);  
                    continue;  
                }  
  
                if (activityInstance_1.getEndTime().before(  
                        activityInstance_2.getEndTime())) {  
                    tempList.remove(activity_1);  
                } else {  
                    tempList.remove(activity_2);  
                }  
            } else {  
                break;  
            }  
        }  
        if (tempList.size() > 0) {  
            return tempList.get(0);  
        }  
        return null;  
    } 
    
    /**
     * @Description: 查询指定任务节点的最新记录  .<br>
     * @param processInstance 流程实例 .<br>
     * @param activityId 活动节点Id.<br>
     * @return HistoricActivityInstance .<br> 
     * @author 郑成功 .<br>
     * @date 2017-9-21 上午11:15:06.<br>
     */
    private HistoricActivityInstance findHistoricUserTask(ProcessInstance processInstance, String activityId) {  
        HistoricActivityInstance rtnVal = null;  
        // 查询当前流程实例审批结束的历史节点  
        List<HistoricActivityInstance> historicActivityInstances = historyService  
                .createHistoricActivityInstanceQuery().activityType(Config.activiNodeType.userTask.toString())  
                .processInstanceId(processInstance.getId()).activityId(  
                        activityId).finished()  
                .orderByHistoricActivityInstanceEndTime().desc().list();  
        if (historicActivityInstances.size() > 0) {  
            rtnVal = historicActivityInstances.get(0);  
        }  
  
        return rtnVal;  
    } 
    
    /**
     * @Description: 根据当前节点，查询输出流向是否为并行终点，如果为并行终点，则拼装对应的并行起点ID .<br>
     * @param @param activityImpl 当前节点  .<br>
     * @return String 拼装并行起点Id.<br> 
     * @author 郑成功 .<br>
     * @date 2017-9-21 上午11:13:58.<br>
     */
    private String findParallelGatewayId(ActivityImpl activityImpl) {  
        List<PvmTransition> incomingTransitions = activityImpl  
                .getOutgoingTransitions();  
        for (PvmTransition pvmTransition : incomingTransitions) {  
            TransitionImpl transitionImpl = (TransitionImpl) pvmTransition;  
            activityImpl = transitionImpl.getDestination();  
            String type = (String) activityImpl.getProperty(Config.constant.type.toString());  
            if (Config.activiNodeType.parallelGateway.toString().equals(type)) {// 并行路线  
                String gatewayId = activityImpl.getId();  
                String gatewayType = gatewayId.substring(gatewayId  
                        .lastIndexOf(Config.UNDERLINE) + 1);  
                if (Config.activiNodeType.end.toString().equals(gatewayType.toLowerCase())) {  
                    return gatewayId.substring(0, gatewayId.lastIndexOf(Config.UNDERLINE))  
                            + Config.UNDERLINE+Config.activiNodeType.start.toString();  
                }  
            }  
        }  
        return null;  
    }

    /**
	 * @Description: 根据流程实例ID和任务key值查询所有同级任务集合  .<br>
	 * @param processInstanceId 流程实例Id .<br>
	 * @param key 任务key值 .<br>
	 * @return List<Task> 任务集合  .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 上午11:09:31.<br>
	 */
	@Override
	public List<Task> findTaskListByKey(String processInstanceId, String key) {
		return taskService.createTaskQuery().processInstanceId(  
                processInstanceId).taskDefinitionKey(key).list(); 
	}
	
	public static String getNextNode(String procInstanceId){
        // 1、首先是根据流程ID获取当前任务：
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procInstanceId).list();
        String nextId = "";
        for (Task task : tasks) {
            // 2、然后根据当前任务获取当前流程的流程定义，然后根据流程定义获得所有的节点：
            ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                    .getDeployedProcessDefinition(task.getProcessDefinitionId());
            List<ActivityImpl> activitiList = def.getActivities(); // rs是指RepositoryService的实例
            // 3、根据任务获取当前流程执行ID，执行实例以及当前流程节点的ID：
            String excId = task.getExecutionId();
            ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(excId).singleResult();
            String activitiId = execution.getActivityId();
            // 4、然后循环activitiList
            // 并判断出当前流程所处节点，然后得到当前节点实例，根据节点实例获取所有从当前节点出发的路径，然后根据路径获得下一个节点实例：
            for (ActivityImpl activityImpl : activitiList) {
                String id = activityImpl.getId();
                if (activitiId.equals(id)) {
                    List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();// 获取从某个节点出来的所有线路
                    for (PvmTransition tr : outTransitions) {
                        PvmActivity ac = tr.getDestination(); // 获取线路的终点节点
                        System.out.println("下一步任务任务：" + ac.getProperty("name"));
                        nextId = ac.getId();
                    }
                    break;
                }
            }
        }
        return nextId;
    }

	/**
	 * @Description: 根据流程实例Id,查询流程实例 .<br>
	 * @param processInstanceId 流程实例Id .<br>
	 * @return ProcessInstance 返回流程实例.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午5:09:50.<br>
	 */
	@Override
	public ProcessInstance findProcessInstance(String processInstanceId) {
		try {
			ProcessInstance pi = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).singleResult();
			return pi;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 根据流程实例Id,查询历史流程实例集合 .<br>
	 * @param instanceId 流程实例Id.<br>
	 * @return List<HistoricActivityInstance> 返回历史流程实例集合.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午3:15:14.<br>
	 */
	@Override
	public List<HistoricActivityInstance> getHistoricActivityInstances(String instanceId) {
		try {
			List<HistoricActivityInstance> activityInstances = historyService
					.createHistoricActivityInstanceQuery()
					.processInstanceId(instanceId)
					.orderByHistoricActivityInstanceId().asc()
					.list();//获取流程走过的节点，并按照节点生成先后顺序排序
			return activityInstances;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 根据处理人，查询个人历史处理处理信息 .<br>
	 * @param assignee 处理人 .<br>
	 * @return List<HistoricTaskInstance> 历史审批任务.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午3:18:08.<br>
	 */
	@Override
	public List<HistoricTaskInstance> getHisTaskList(String assignee) {
		try {
			List<HistoricTaskInstance> list = historyService
					.createHistoricTaskInstanceQuery()
					.taskAssignee(assignee)
					.orderByTaskId()
					.desc()
					.list();
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 根据处理人，查询当前任务的审批记录 .<br>
	 * @param assignee 处理人 .<br>
	 * @return List<HistoricTaskInstance> 历史审批任务.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午3:18:08.<br>
	 */
	@Override
	public List<HistoricTaskInstance> getHisTaskByTaskId(String taskId) {
		//获取正在运行的任务
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		if(task!=null){
			String processInstanceId = task.getProcessInstanceId();
			List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery()
					.processInstanceId(processInstanceId).orderByTaskId().asc().list();
			return hisTasks;
		}
		return null;
	}
	
	/**
	 * @Description: 根据处理人，查询个人历史处理处理信息 .<br>
	 * @param assignee 处理人 .<br>
	 * @return List<HistoricTaskInstance> 历史审批任务.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午3:18:08.<br>
	 */
	@Override
	public List<HistoricTaskInstance> getHisTask(String billId, String key) {
		try {
			/*HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
					.processInstanceBusinessKey(billId).processDefinitionKey(key)
					.orderByProcessInstanceStartTime().desc().list().get(0);*/
			HistoricProcessInstance hpi = getHisProInst(billId);
			String processInstanceId = hpi.getId();
			return historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
						.orderByTaskCreateTime().asc().list();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 通过任务Id,获取批注信息 .<br>
	 * @param taskId 当前任务Id.<br>
	 * @return List<Comment> 返回审批批注.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午5:18:55.<br>
	 */
	@Override
	public List<Comment> findCommentByTaskId(String taskId) {
		try {
			List<Comment> list = new ArrayList<Comment>();
			//使用当前任务ID，获取当前任务对象
			Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
			//获取流程实例ID
			String processInstanceId = task.getProcessInstanceId();
			list = taskService.getProcessInstanceComments(processInstanceId);
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 通过单据Id和key值，获取批注信息 .<br>
	 * @param billId 单据Id .<br>
	 * @param key key值 .<br>
	 * @return List<Comment> 返回审批批注 .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午5:20:03.<br>
	 */
	@Override
	public List<Comment> findCommentByBillId(String billId, String key) {
		try {
			HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
					.processInstanceBusinessKey(billId).processDefinitionKey(key)
					.orderByProcessInstanceStartTime().desc().list().get(0);
			String processInstanceId = hpi.getId();
			return taskService.getProcessInstanceComments(processInstanceId);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 获取单列流程实例 .<br>
	 * @param instanceId 流程实例Id .<br>
	 * @return HistoricProcessInstance 返回历史流程实例 .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午5:21:33.<br>
	 */
	@Override
	public HistoricProcessInstance getHistoricProcessInstance(String instanceId) {
		try {
			HistoricProcessInstance historicProcessInstance = historyService
					.createHistoricProcessInstanceQuery()
					.processInstanceId(instanceId).singleResult();
			return historicProcessInstance;	
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * @Description: 根据当前任务Id,获取历史审批信息及批注信息 .<br>
	 * @param taskId  当前任务Id .<br>
	 * @return List<HistoryTaskComment> 历史任务审批及批注.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-21 下午10:38:04 .<br>
	 */
	@Override
	public List<HistoryTaskComment> findTaskComment(String taskId) {
		List<HistoryTaskComment> taskComments = new ArrayList<HistoryTaskComment>();
		//获取历史任务信息
		List<HistoricTaskInstance> hisTask = getHisTaskByTaskId(taskId);
		//获取历史批注信息
		List<Comment> hisComments = findCommentByTaskId(taskId);
		for(HistoricTaskInstance ht:hisTask){
			if(ht.getEndTime()!=null){
				HistoryTaskComment htc = new HistoryTaskComment();
				htc.setId(ht.getId());
				htc.setName(ht.getName());
				htc.setAssignee(ht.getAssignee());
				htc.setStartTime(ht.getStartTime());
				htc.setEndTime(ht.getEndTime());
				htc.setDurationInMillis(ht.getDurationInMillis()/60000);
				for(Comment hc:hisComments){
					if(ht.getId().equals(hc.getTaskId())){
						htc.setHistoryCommentId(hc.getId());
						htc.setUserId(hc.getUserId());
						htc.setOperateType(hc.getType());
						htc.setMessage(hc.getFullMessage());
					}
				}
				taskComments.add(htc);
			}
		}
		return taskComments;
	}


	@Override
	public boolean jumpTask(String taskId, String targetTaskDefinitionKey, Map<String,Object> variables,String reason) throws TaskException {
		try {
			//通过任务Id,获取正在执行的任务信息
			final TaskEntity task = (TaskEntity)taskService.createTaskQuery().taskId(taskId).singleResult();
			String executionId = task.getExecutionId();
			BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
			//通过任务Id和
			final ActivityImpl activity = findActivitiImpl(taskId, targetTaskDefinitionKey);
			final ExecutionEntity execution = (ExecutionEntity)runtimeService.createExecutionQuery()
	        		.executionId(task.getExecutionId()).singleResult();
	        ((RuntimeServiceImpl)runtimeService).getCommandExecutor().execute(new Command<java.lang.Void>() {
	            public Void execute(CommandContext commandContext) {
	                //创建新任务
	                execution.setActivity(activity);
	                execution.executeActivity(activity);
	                //删除当前的任务
	                //不能删除当前正在执行的任务，所以要先清除掉关联
	                task.setExecutionId(null);
	                taskService.saveTask(task);
	                taskService.deleteTask(task.getId(),true);
	                return null;
	            }
	        });
	        //是否需要回调
			callFlowClass(billBean,Contacts.JUMP_FLOW_TYPE, billBean.getBillId());
	        return true;
		} catch (Exception e) {
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.转办异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}

	/**
	 * @Description: 根据单据Id,获取单据的最新流程实例 .<br>
	 * @param billId 单据Id.<br>
	 * @return HistoricProcessInstance .<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-28 下午4:09:13.<br>
	 */
	@Override
	public HistoricProcessInstance getHisProInst(String billId) {
		List<HistoricProcessInstance> hpiList = historyService.createHistoricProcessInstanceQuery()
				.processInstanceBusinessKey(billId)
				.orderByProcessInstanceStartTime()
				.desc()
				.list();
		if(hpiList.size()>0){
			HistoricProcessInstance preInst = hpiList.get(0);
			if(preInst.getDeleteReason()==null||preInst.getDeleteReason().equals("")){
				return preInst;
			}
			return null;
		}
		return null;
	}
	
	@Override
	public List<HistoryTaskComment> findTaskCommentByBillId(String billId){
		HistoricProcessInstance hisProInst = getHisProInst(billId);
		if(hisProInst!=null){
			String key = hisProInst.getProcessDefinitionKey();
			return findTaskComment(billId,key);
		}
		return new ArrayList<HistoryTaskComment>();
	}
	
	@Override
	public Map<String,List<HistoryTaskComment>> findTaskCommentMapByBillId(String billId){
		Map<String,List<HistoryTaskComment>> taskCommentMaps = new HashMap<String, List<HistoryTaskComment>>();
		HistoricProcessInstance hisProInst = getHisProInst(billId);
		if(hisProInst!=null){
			String proDefId = hisProInst.getProcessDefinitionId();
			BpmnModel model = repositoryService.getBpmnModel(proDefId);
			List<UserTask> list = findUserTaskByModel(model);
			List<HistoryTaskComment> taskComments = findTaskCommentByBillId(billId);
			for(UserTask userTask:list){
				List<HistoryTaskComment> hisTaskComments = new ArrayList<HistoryTaskComment>();
				for(HistoryTaskComment taskComment:taskComments){
					if(userTask.getId().equals(taskComment.getTaskDefinitionKey())){
						hisTaskComments.add(taskComment);
					}
				}
				taskCommentMaps.put(userTask.getId(), hisTaskComments);
			}
		}
		return taskCommentMaps;
	}

	/**
	 * @Description: 通过单据Id和key，查询单据的审批任务 .<br>
	 * @param billId 单据Id.<br>
	 * @param key 启动流程的key值.<br>
	 * @return List<HistoryTaskComment> 历史审批意见.<br> 
	 * @author 郑成功 .<br>
	 * @date 2017-9-28 下午4:20:49.<br>
	 */
	@Override
	public List<HistoryTaskComment> findTaskComment(String billId, String key) {
		List<User> users = userService.selectList(null);
		List<HistoryTaskComment> taskComments = new ArrayList<HistoryTaskComment>();
		//获取历史任务信息
		List<HistoricTaskInstance> hisTask = getHisTask(billId, key);
		//获取历史批注信息
		List<Comment> hisComments = findCommentByBillId(billId, key);
		for(HistoricTaskInstance ht:hisTask){
			if(ht.getEndTime()!=null){
				HistoryTaskComment htc = new HistoryTaskComment();
				htc.setId(ht.getId());
				htc.setTaskDefinitionKey(ht.getTaskDefinitionKey());
				htc.setName(ht.getName());
				htc.setAssignee(ht.getAssignee());
				htc.setStartTime(ht.getStartTime());
				htc.setEndTime(ht.getEndTime());
				htc.setDurationInMillis(ht.getDurationInMillis()/60000);
				htc.setUserName(UserUtils.getUser(ht.getAssignee(), users).getRealname());
				for(Comment hc:hisComments){
					if(ht.getId().equals(hc.getTaskId())){
						htc.setHistoryCommentId(hc.getId());
						htc.setUserId(hc.getUserId());
						htc.setOperateType(hc.getType());
						htc.setMessage(hc.getFullMessage());
					}
				}
				taskComments.add(htc);
			}
		}
		return taskComments;
	}


	@Override
	public InputStream getFlowChart(String taskOrProInstId) {
		HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(taskOrProInstId).singleResult();
		if(hpi==null){
			taskOrProInstId = historyService.createHistoricTaskInstanceQuery().taskId(taskOrProInstId).singleResult().getProcessInstanceId();
		}
		return getFlowImg(taskOrProInstId);
	}
	
	@Override
	public InputStream getCustomFlowChart(String taskOrProInstId) {
		HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(taskOrProInstId).singleResult();
		if(hpi==null){
			taskOrProInstId = historyService.createHistoricTaskInstanceQuery().taskId(taskOrProInstId).singleResult().getProcessInstanceId();
		}
		Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd(taskOrProInstId);  
		InputStream is = managementService.executeCommand(cmd);  
		return is;
	}


	@Override
	public InputStream getBillCustomFlowChart(String billId) {
		HistoricProcessInstance  proInst = getHisProInst(billId);
		if(proInst!=null){
			Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd(proInst.getId());  
			InputStream is = managementService.executeCommand(cmd);  
			return is;
		}
		return null ;
	}
	

	@Override
	public InputStream getFlowChartBillId(String billId) {
		HistoricProcessInstance  hisProInst = getHisProInst(billId);
		if(hisProInst!=null){
			return getFlowImg(hisProInst.getProcessDefinitionId());
		}
		return null;
	}


	@Override
	public InputStream getFlowChartByProInstId(String processInstanceId) {
		return getFlowImg(processInstanceId);
	}
	
	/**
	 * @Description: 通过流程实例Id，获取流程图 .<br>
	 * @param processInstanceId 流程实例Id.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-7-25 上午10:52:14.<br>
	 */
	private InputStream getFlowImg(String processInstanceId){
		//获取历史流程实例
	    HistoricProcessInstance processInstance =  historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
	    //获取流程图
	    BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
	    processEngineConfiguration = processEngine.getProcessEngineConfiguration();
	    Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);

	    ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
	    ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());

	    List<HistoricActivityInstance> highLightedActivitList =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
	    //高亮环节id集合
	    List<String> highLightedActivitis = new ArrayList<String>();
	    //高亮线路id集合
	    List<String> highLightedFlows = getHighLightedFlows(definitionEntity,highLightedActivitList);

	    for(HistoricActivityInstance tempActivity : highLightedActivitList){
           	String activityId = tempActivity.getActivityId();
           	highLightedActivitis.add(activityId);
       	}
	    //当前流程实例执行到哪个节点
	    ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(processInstanceId).singleResult();// 执行实例
	    if(execution!=null){
	    	highLightedActivitis.add(execution.getActivityId());
	    }
	    //中文显示的是口口口，设置字体就好了
	    InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis,highLightedFlows,"宋体","宋体",null,null,1.0);
	    return imageStream;
	}
	
	/**
	    * 获取需要高亮的线
	    * @param processDefinitionEntity
	    * @param historicActivityInstances
	    * @return
	    */
	   private List<String> getHighLightedFlows(
	           ProcessDefinitionEntity processDefinitionEntity,
	           List<HistoricActivityInstance> historicActivityInstances) {
	       List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
	       for (int i = 0; i < historicActivityInstances.size() - 1; i++) {// 对历史流程节点进行遍历
	           ActivityImpl activityImpl = processDefinitionEntity
	                   .findActivity(historicActivityInstances.get(i)
	                           .getActivityId());// 得到节点定义的详细信息
	           List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();// 用以保存后需开始时间相同的节点
	           ActivityImpl sameActivityImpl1 = processDefinitionEntity
	                   .findActivity(historicActivityInstances.get(i + 1)
	                           .getActivityId());
	           // 将后面第一个节点放在时间相同节点的集合里
	           sameStartTimeNodes.add(sameActivityImpl1);
	           for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
	               HistoricActivityInstance activityImpl1 = historicActivityInstances
	                       .get(j);// 后续第一个节点
	               HistoricActivityInstance activityImpl2 = historicActivityInstances
	                       .get(j + 1);// 后续第二个节点
	               if (activityImpl1.getStartTime().equals(
	                       activityImpl2.getStartTime())) {
	                   // 如果第一个节点和第二个节点开始时间相同保存
	                   ActivityImpl sameActivityImpl2 = processDefinitionEntity
	                           .findActivity(activityImpl2.getActivityId());
	                   sameStartTimeNodes.add(sameActivityImpl2);
	               } else {
	                   // 有不相同跳出循环
	                   break;
	               }
	           }
	           List<PvmTransition> pvmTransitions = activityImpl
	                   .getOutgoingTransitions();// 取出节点的所有出去的线
	           for (PvmTransition pvmTransition : pvmTransitions) {
	               // 对所有的线进行遍历
	               ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition
	                       .getDestination();
	               // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
	               if (sameStartTimeNodes.contains(pvmActivityImpl)) {
	                   highFlows.add(pvmTransition.getId());
	               }
	           }
	       }
	       return highFlows;
	   }


	@Override
	public List<FlowElement> findActDefKeyList(String taskId) {
		List<FlowElement> flowElements = new ArrayList<FlowElement>();
		ProcessDefinitionEntity def = findProcessDefinitionEntityByTaskId(taskId);
		String preDefId = def.getId();
		BpmnModel model = repositoryService.getBpmnModel(preDefId);  
		if(model != null) {  
		    flowElements = (List<FlowElement>) model.getMainProcess().getFlowElements();  
		} 
		return flowElements;
	}


	@Override
	public List<ActivityImpl> findAvtivitiList(String taskId) {
		ProcessDefinitionEntity def = findProcessDefinitionEntityByTaskId(taskId);
		String preDefId = def.getId();
		List<FlowElement> flowElements = new ArrayList<FlowElement>();
		BpmnModel model = repositoryService.getBpmnModel(preDefId);  
		if(model != null) {  
		    flowElements = (List<FlowElement>) model.getMainProcess().getFlowElements();  
		}
		return sortActivityImpl(def.getActivities(),flowElements,true);  
	}


	@Override
	public boolean claimTask(String taskId, String claimer) throws TaskException {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		//签收
		try {
			String executionId = task.getExecutionId();
			BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
			taskService.claim(task.getId(), claimer);
			//是否需要回调
			callFlowClass(billBean,Contacts.CLAIM_FLOW_TYPE, billBean.getBillId());
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.签收异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}


	@Override
	public List<UserTask> findUserTasks(String modelId) {
		List<UserTask> list = new ArrayList<UserTask>();
		try {
			byte[] byts = repositoryService.getModelEditorSource(modelId);
			BpmnJsonConverter jc = new BpmnJsonConverter();
			BpmnModel model = new BpmnModel();
			JsonNode  editorNode = new ObjectMapper().readTree(byts);			
			model = jc.convertToBpmnModel(editorNode);
			if(model != null){
				Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();			
				for(FlowElement e:flowElements){
					if(e instanceof UserTask){
						UserTask userTask = (UserTask) e;
						list.add(userTask);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}


	@Override
	public List<HistoricTaskInstanceEntity> findUniqueHisTasks(String billId) {
		List<HistoricTaskInstanceEntity> list = new ArrayList<HistoricTaskInstanceEntity>();
		HistoricProcessInstance proInst = getHisProInst(billId);
		Map<String,Object> map = new LinkedHashMap<String, Object>();
		if(proInst!=null){
			String preDefKey = proInst.getProcessDefinitionKey();
			List<HistoricTaskInstance> hisTaskList = getHisTask(billId, preDefKey);
			for(HistoricTaskInstance hisTask:hisTaskList){
				HistoricTaskInstanceEntity histask = new HistoricTaskInstanceEntity();
				for(HistoricTaskInstance his:hisTaskList){
					if(hisTask.getTaskDefinitionKey().equals(his.getTaskDefinitionKey())){
						histask = (HistoricTaskInstanceEntity) hisTask;
						map.put(hisTask.getTaskDefinitionKey(), histask);
					}
				}
			}
			for (Object value : map.values()) {  
				list.add((HistoricTaskInstanceEntity)value);
			}
			return list;
		}
		return new ArrayList<HistoricTaskInstanceEntity>();
	}


	@Override
	public BpmnModel findModel(String billId) {
		HistoricProcessInstance  hisProInst = getHisProInst(billId);
		String preDefId = hisProInst.getProcessDefinitionId();
		BpmnModel model = repositoryService.getBpmnModel(preDefId);
		return model;
	}


	@Override
	public List<UserTask> findUserTaskByModel(BpmnModel model) {
		List<UserTask> list = new ArrayList<UserTask>();
		try {
			if(model != null){
				Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();			
				for(FlowElement e:flowElements){
					if(e instanceof UserTask){
						UserTask userTask = (UserTask) e;
						userTask.getCustomProperties();
						Map<String, List<ExtensionElement>> map = userTask.getExtensionElements();
						List<CustomProperty> customList = userTask.getCustomProperties();
						for (Map.Entry<String, List<ExtensionElement>> entry : map.entrySet()) {
							   String key = entry.getKey().toString();
							   List<ExtensionElement> eseList = entry.getValue();
							   if(key.equals(ExtProperty.SORT_NUM)||key.equals(ExtProperty.SEND_MSG_TEMPLET)){
								   for(ExtensionElement ese:eseList){
									   CustomProperty customProperty = new CustomProperty();
									   customProperty.setName(ese.getName());
									   customProperty.setSimpleValue(ese.getElementText());
									   customList.add(customProperty);
								   }
							   }
						}
						list.add(userTask);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		for (int i = 0; i < list .size(); i++)    {  
	        for (int j = list .size()-1; j > i; j--)  {
	        	CustomProperty cp = getCustomProperty(list.get(j),ExtProperty.SORT_NUM);
	        	CustomProperty cp2 = getCustomProperty(list.get(j-1),ExtProperty.SORT_NUM);
	            String sort1 = cp!=null?cp.getSimpleValue():String.valueOf(10);
	            String sort2 = cp2!=null?cp2.getSimpleValue():String.valueOf(10);
	            if (Integer.valueOf(sort1).compareTo(Integer.valueOf(sort2))<0)    {  
	            	//互换位置
	            	UserTask  ut = list.get(j);
	                list.set(j, list.get(j-1));
	                list.set(j-1, ut );
	            }  
	        }  
	    } 
		return list;
	}


	@Override
	public List<TaskEntity> findTaskList(String billId) {
		List<TaskEntity> tasks = new ArrayList<TaskEntity>();
		HistoricProcessInstance proInst = getHisProInst(billId);
		if(proInst!=null){
			String proInstId = proInst.getId();
			List<Task> list = taskService.createTaskQuery().processInstanceId(proInstId).list();
			for(Task t:list){
				tasks.add((TaskEntity)t);
			}
		}
		return tasks;
	}


	@Override
	public boolean complate(String taskId, OperateBean operate) throws TaskException {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		String executionId = task.getExecutionId();
		
		User user = UserUtils.getUser();
		AssigneeInfo assigneeInfo = new AssigneeInfo();
		assigneeInfo.setAssigneeId(user.getId());
		assigneeInfo.setAssigneeName(user.getRealname());
		BillBean billBean = runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
		//查询单据信息
		String billId = billBean.getBillId();
		String tableName = billBean.getTableName();
		String idFeild = billBean.getIdFeild();
		Map<String,Object> billInfo = flowCommonService.findBillInfo(billId, tableName, idFeild);
		return completeTask(taskId, operate, assigneeInfo, false, billInfo);
	}


	@Override
	public List<HistoricTaskInstanceEntity> findUniqueHisTasksToRunTask(
			String billId) {
		List<HistoricTaskInstanceEntity> newHisTasks = new ArrayList<HistoricTaskInstanceEntity>();
		List<TaskEntity> tasks = findTaskList(billId);
		List<HistoricTaskInstanceEntity> hisTasks = findUniqueHisTasks(billId);
		for(HistoricTaskInstanceEntity his:hisTasks){
			boolean flag = true;
			for(TaskEntity task:tasks){
				if(task.getTaskDefinitionKey().equals(his.getTaskDefinitionKey())){
					flag = false;
					break;
				}
			}
			if(flag){
				newHisTasks.add(his);
				continue;
			}else{
				newHisTasks.add(his);
				continue;
			}
		}
		return newHisTasks;
	}


	@Override
	public List<HistoryTaskComment> findUniqueTaskComment(String billId) {
		List<HistoryTaskComment> comments = new ArrayList<HistoryTaskComment>();
		List<User> users = userService.selectList(null);
		HistoricProcessInstance proInst = getHisProInst(billId);
		if(proInst!=null){
			//获取最新审批记录
			List<HistoricTaskInstanceEntity> hisTasks = findUniqueHisTasksToRunTask(billId);
			//获取历史批注信息
			List<Comment> hisComments = findCommentByBillId(billId, proInst.getProcessDefinitionKey());
			for(HistoricTaskInstance ht:hisTasks){
				//if(ht.getEndTime()!=null){
					HistoryTaskComment htc = new HistoryTaskComment();
					htc.setId(ht.getId());
					htc.setName(ht.getName());
					htc.setAssignee(ht.getAssignee());
					htc.setUserName(UserUtils.getUser(ht.getAssignee(), users).getRealname());
					htc.setStartTime(ht.getStartTime());
					htc.setEndTime(ht.getEndTime());
					htc.setTaskDefinitionKey(ht.getTaskDefinitionKey());
					htc.setDurationInMillis(ht.getDurationInMillis()!=null?ht.getDurationInMillis()/60000:null);
					for(Comment hc:hisComments){
						if(ht.getId().equals(hc.getTaskId())){
							htc.setHistoryCommentId(hc.getId());
							htc.setUserId(hc.getUserId());
							htc.setOperateType(hc.getType());
							htc.setMessage(hc.getFullMessage());
							htc.setOperateTime(hc.getTime());
						}
					}
					comments.add(htc);
				//}
			}
		}
		return comments;
	}
	
	@Override
	public List<HistoryTaskComment> findUniqueCommentToTask(String billId) {
		List<HistoryTaskComment> newHisConments = new ArrayList<HistoryTaskComment>();
		List<HistoryTaskComment> hisComments = findUniqueTaskComment(billId);
		HistoricProcessInstance proInst = getHisProInst(billId);
		List<Task> tasks = taskService.createTaskQuery().processInstanceId(proInst.getId()).list();
		List<String> list = new ArrayList<String>();
		for(Task task:tasks){
			list.add(task.getTaskDefinitionKey());
		}
		for(HistoryTaskComment hisTask:hisComments){
			if(list.contains(hisTask.getTaskDefinitionKey())){
				break;
			}
			newHisConments.add(hisTask);
		}
		return newHisConments;
	}


	@Override
	public List<Task> findMyTasks(String assignee) {
		List<Task>  list = taskService
				.createTaskQuery()
				.taskAssignee(assignee)
				.orderByTaskCreateTime()
				.desc()
				.list();
		return list;
	}


	@Override
	public boolean saveUserGroup(String groupId, List<String> userIds) {
		try {
			for(String userId:userIds){
				identityService.createMembership(userId, groupId);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}


	@Override
	public boolean deleteGroupUser(String groupId, List<String> userIds) {
		try {
			for(String userId:userIds){
				identityService.deleteMembership(userId, groupId);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}


	@Override
	public CustomProperty getCustomProperty(UserTask userTask,String propertyName) {
		List<CustomProperty> list = userTask.getCustomProperties();
		for(CustomProperty cp:list){
			if(cp.getName().equals(propertyName)){
				return cp;
			}
		}
		return null;
	}


	@Override
	public UserTask getUserTaskByTaskId(String taskId, String taskDefKey) {
		HistoricTaskInstance  hisTask = historyService
				.createHistoricTaskInstanceQuery()
				.taskId(taskId)
				.singleResult();
		String preDefId = hisTask.getProcessDefinitionId();
		BpmnModel model = repositoryService.getBpmnModel(preDefId);
		return getUserTask(model, taskDefKey);
	}


	@Override
	public UserTask getUserTaskByPreDefId(String preDefId, String taskDefKey) {
		BpmnModel model = repositoryService.getBpmnModel(preDefId);
		return getUserTask(model, taskDefKey);
	}


	@Override
	public UserTask getUserTaskByProInstId(String proInstId, String taskDefKey) {
		HistoricProcessInstance hisProInst = historyService
				.createHistoricProcessInstanceQuery()
				.processInstanceId(proInstId)
				.singleResult();
		String preDefId = hisProInst.getProcessDefinitionId();
		BpmnModel model = repositoryService.getBpmnModel(preDefId);
		return getUserTask(model, taskDefKey);
	}


	@Override
	public UserTask getUserTaskByModelId(String modelId, String taskDefKey) {
		UserTask userTask = new UserTask();
		try {
			byte[] byts = repositoryService.getModelEditorSource(modelId);
			JsonNode  editorNode = new ObjectMapper().readTree(byts);
			BpmnJsonConverter jc = new BpmnJsonConverter();
			BpmnModel model = jc.convertToBpmnModel(editorNode);
			model = jc.convertToBpmnModel(editorNode);
			return getUserTask(model, taskDefKey);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return userTask;
	}
	
	/**
	 * @Description: 从模型里面取得指定任务节点的相关属性 .<br>
	 * @param model 模型 .<br>
	 * @param taskDefKey 任务节点Key.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-7-25 上午11:13:04.<br>
	 */
	private UserTask getUserTask(BpmnModel model,String taskDefKey){
		UserTask userTask = new UserTask();
		if(model != null){
			Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();			
			for(FlowElement e:flowElements){
				if(e instanceof UserTask){
					if(taskDefKey.equals(e.getId())){
						userTask = (UserTask) e;
						userTask.getCustomProperties();
						Map<String, List<ExtensionElement>> map = userTask.getExtensionElements();
						List<CustomProperty> customList = userTask.getCustomProperties();
						for (Map.Entry<String, List<ExtensionElement>> entry : map.entrySet()) {
							   String key = entry.getKey().toString();
							   List<ExtensionElement> list = entry.getValue();
							   if(key.equals(ExtProperty.SORT_NUM)||key.equals(ExtProperty.SEND_MSG_TEMPLET)){
								   for(ExtensionElement ese:list){
									   CustomProperty customProperty = new CustomProperty();
									   customProperty.setName(ese.getName());
									   customProperty.setSimpleValue(ese.getElementText());
									   customList.add(customProperty);
								   }
							   }
						}
					}
				}
			}
		}
		return userTask;
	}


	@Override
	public String getStartActUserIdByTask(String taskId) {
		HistoricTaskInstance  hisTask = historyService
				.createHistoricTaskInstanceQuery()
				.taskId(taskId)
				.singleResult();
		String proInstId = hisTask.getProcessInstanceId();
		return getStartActUserIdByProInst(proInstId);
	}


	@Override
	public String getStartActUserIdByProInst(String proInstId) {
		HistoricProcessInstance hisProInst = historyService
				.createHistoricProcessInstanceQuery()
				.processInstanceId(proInstId)
				.singleResult();
		return hisProInst.getStartUserId();
	}

	/**
	 * @Description: 获取流程单据信息 .<br>
	 * @param billBean 实体类.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-7-25 下午2:10:50.<br>
	 */
	@Override
	public Map<String,Object> getBillInfo(BillBean billBean){
		//查询单据信息
		String billId = billBean.getBillId();
		String idFeild = billBean.getIdFeild();
		Map<String,Object> billInfo = new HashMap<String, Object>();
		if(StringUtils.isNotEmpty(billBean.getCustomSql())){
			billInfo = flowCommonService.findCustomSql(billBean.getCustomSql());
		}else{
			billInfo = flowCommonService.findBillInfo(billId, billBean.getTableName(), idFeild);
		}
		return billInfo;
	}

	@Override
	public boolean updateBillStatus(int status,BillBean billBean){
		try {
			String billId = billBean.getBillId();
			String tableName = billBean.getTableName();
			String idFeild = billBean.getIdFeild();
			String statusFeild = billBean.getStatusFeild();
			flowCommonService.updateBillStatus(billId, tableName, idFeild, statusFeild, status);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}


	@Override
	public Task getTask(String taskId) {
		return taskService.createTaskQuery().taskId(taskId).singleResult();
	}


	@Override
	public BillBean getBillBean(String executionId) {
		return runtimeService.getVariable(executionId, Config.variable.表单信息.toString(), BillBean.class);
	}


	@Override
	public List<HistoricTaskInstanceEntity> findHisTask(String billId) {
		List<HistoricTaskInstanceEntity> hisTaskList = new ArrayList<HistoricTaskInstanceEntity>();
		HistoricProcessInstance hisProInst = getHisProInst(billId);
		if(hisProInst!=null){
			String hisProInstId = hisProInst.getId();
			List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery()
					.processInstanceId(hisProInstId)
					.orderByTaskCreateTime()
					.asc()
					.list();
			for(HistoricTaskInstance hisTask:hisTasks){
				HistoricTaskInstanceEntity taskEntity = new HistoricTaskInstanceEntity();
				taskEntity = (HistoricTaskInstanceEntity) hisTask;
				hisTaskList.add(taskEntity);
			}
			return hisTaskList;
		}
		return new ArrayList<HistoricTaskInstanceEntity>();
	}


	@Override
	public boolean reminderTask(String proInstId,String msg) throws TaskException {
		List<User> users = userService.selectList(null);
		try {
			List<Task> tasks = taskService.createTaskQuery().processInstanceId(proInstId).list();
			for(Task task:tasks){
				List<String> newUserIds = getUserIds(task);
				List<String> phones = getPhones(newUserIds, users);
				//发送短信
				SpringContextHolder.getBean(ActivitiFlowService.class)
						.sendSMS(task.getExecutionId(), StringUtils.join(phones, ","), msg,null);
			}
			return true;
		} catch (Exception e) {
			String className = Thread.currentThread().getStackTrace()[1].getClassName();
			String message = StackTraceElementUtils.getExceptionMessage(FlowMessage.催办异常.toString(), className, e);
			throw new TaskException(message,e);
		}
	}
	
	/**
	 * @Description: 审批更新单据 .<br>
	 * @param taskId 任务Id.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-8-24 下午4:18:34.<br>
	 */
	@Override
	public AjaxJson updateBill(Task task,BillBean billBean){
		AjaxJson j = new AjaxJson();
		int status = Contacts.AUDITED;
		//任务是否办理成功，办理成功后，处理相关业务，列如发送短信
		flowService.sendSms(billBean.getBillId());
		ProcessInstance pi = flowService.findProcessInstance(task.getProcessInstanceId());
		j.setMsg("流程审批成功");
		if(pi==null){
			//修改单据状态
			boolean updateStatus = flowService.updateBillStatus(status, billBean);
			if(!updateStatus){
				j.setRet(AjaxJson.RET_FAIL);
				j.setMsg("流程审批成功,更新单据状态失败");
			}
		}
		return j;
	}
	
	/**
	 * @Description: 回调方法，提供给流程处理结束后调用 .<br>
	 * @param billBean 单据信息.<br>
	 * @param type 处理类型.<br>
	 * @param billId 单据Id.<br>   
	 * @author 郑成功 .<br>
	 * @throws TaskException 
	 * @date 2018-9-6 下午2:29:49.<br>
	 */
	@Override
	public void callFlowClass(BillBean billBean,String type,String billId) throws TaskException{
		if(billBean.isCallBack()){
			try {
				Class<?> c = ClassUtil.getEntityClass(billBean.getCallClass());
				Class[] argTypes=new Class[2];
				argTypes[0]=String.class;
				argTypes[1]=BillBean.class;
				Method m=c.getDeclaredMethod(billBean.getCallMethod(),argTypes);
				m.invoke(c.newInstance(), new Object[]{type,billBean});
			} catch (Exception e) {
				String className = Thread.currentThread().getStackTrace()[1].getClassName();
				String message = StackTraceElementUtils.getExceptionMessage("回调处理异常", className, e);
				throw new TaskException(message,e);
			}
		}
	}
	
	/**
	 * @Description: 发送短信 .<br>
	 * @param billId 单据Id.<br>   
	 * @author 郑成功 .<br>
	 * @date 2018-8-28 上午10:44:21.<br>
	 */
	@Override
	public void sendSms(String billId){
		//根据单据Id,获取流程实例
		HistoricProcessInstance procInst = flowService.getHisProInst(billId);
		List<User> users = userService.selectList(null);
		if(procInst!=null){
			String proInstId = procInst.getId();
			//根据流程实例,获取任务Id
			List<Task> list = taskService.createTaskQuery().processInstanceId(proInstId).list();
			//找到指定任务的相关处理人或者待签收人
			for(Task t:list){
				List<String> newUserIds = getUserIds(t);
				//获取该节点的短信发送模板
				UserTask userTask = flowService.getUserTaskByProInstId(proInstId, t.getTaskDefinitionKey());
				//获取自定义属性短信发送模板
				CustomProperty customProperty = flowService.getCustomProperty(userTask, ExtProperty.SEND_MSG_TEMPLET);
				if(customProperty!=null){
					List<String> phones = getPhones(newUserIds, users);
					//发送短信
					SpringContextHolder.getBean(ActivitiFlowService.class)
							.sendSMS(t.getExecutionId(), 
							org.apache.commons.lang.StringUtils.join(phones, ","), 
							customProperty.getSimpleValue(),null);
				}
			}
		}
	}
	
	/**
	 * @Description: 得到任务的办理人或者签收人 .<br>
	 * @param task 当前任务.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-12-6 下午2:32:31.<br>
	 */
	private List<String> getUserIds(Task task){
		List<String> newUserIds = new ArrayList<String>();
		List<IdentityLink> idLinks =  taskService.getIdentityLinksForTask(task.getId());
		for(IdentityLink link:idLinks){
			if(StringUtils.isNotEmpty(link.getTaskId())&&link.getTaskId().equals(task.getId())){
				if(StringUtils.isNotEmpty(link.getUserId())){
					newUserIds.add(link.getUserId());
				}else{
					List<org.activiti.engine.identity.User> userList = identityService
							.createUserQuery()
							.memberOfGroup(link.getGroupId())
							.list();
					for(org.activiti.engine.identity.User user:userList){
						newUserIds.add(user.getId());
					}
				}
			}
		}
		return new ArrayList<>(new HashSet<String>(newUserIds));
	}
	
	/**
	 * @Description: 得到电话集合 .<br>
	 * @param userIds 用户Id.<br>
	 * @param users 用户信息.<br>
	 * @author 郑成功 .<br>
	 * @date 2018-7-25 下午5:29:03.<br>
	 */
	private List<String> getPhones(List<String> userIds,List<User> users){
		List<String> phones = new ArrayList<String>();
		for(String id:userIds){
			for(User user:users){
				if(id.equals(user.getId())&&StringUtils.isNotEmpty(user.getPhone())){
					phones.add(user.getPhone());
				}
			}
		}
		return phones;
	}


	@Override
	public BillBean getBillBeanByTaskId(String taskId) {
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		if(task!=null){
			BillBean billInfo =  (BillBean) runtimeService.getVariable(task.getExecutionId(), Config.variable.表单信息.toString());
			if(billInfo!=null){
				return billInfo;
			}
		}
		return null;
	}


	@Override
	public List<PvmTransition> getNextBranches(String taskId) {
		List<Map<String,String>> transList = new ArrayList<Map<String,String>>(); 
		// 获取流程定义
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); 
		ProcessDefinitionEntity pd = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(task.getProcessDefinitionId()); 
		// 获取流程实例 
		ProcessInstance pi =runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); 
		// 获取当前活动的ID 
		String activitiId = pi.getActivityId(); 
		// 获取当前活动对象 
		ActivityImpl activity = pd.findActivity(task.getTaskDefinitionKey());
		// 获取当前对象后续路径
		List<PvmTransition> transitions = activity.getOutgoingTransitions(); 
		// 遍历后续路径，封装至集合返回前台生成按钮
		Map<String,String> map =new HashMap<String,String>();
		return transitions;
	}


	@Override
	public boolean isAllowHitback(String taskId) {
		List<PvmTransition> transitions = getNextBranches(taskId);
		for(PvmTransition pvm:transitions){
			String transRequisite = (String) pvm.getProperty("conditionText");
			if(StringUtils.isNotBlank(transRequisite)&&transRequisite.trim().contains(HIT_REQUISITE)){
				return true;
			}
		}
		return false;
	}
	
	@Override
	public Map<String,Object> getRuVariables(String executionId){
		Map<String,Object> variables =  runtimeService.getVariables(executionId);
		BillBean billBean = (BillBean) variables.get(Config.variable.表单信息.toString());
		variables.remove(Config.constant.submitUser.toString());
		BillActConfig config = billActConfigService.selectById(billBean.getConfigId());
		if(!ObjectUtils.isNullOrEmpty(config)&&StringUtils.isEmpty(billBean.getNoticeTemplet())){
			billBean.setNoticeTemplet(config.getNoticeTemplet());
		}
		if(!ObjectUtils.isNullOrEmpty(config)&&StringUtils.isEmpty(billBean.getTaskAuditeUrl())){
			billBean.setTaskAuditeUrl(config.getTaskAuditeUrl());
		}
		if(!ObjectUtils.isNullOrEmpty(config)&&StringUtils.isEmpty(billBean.getTaskSignUrl())){
			billBean.setTaskSignUrl(config.getTaskSignUrl());
		}
		variables.put(Config.variable.表单信息.toString(), billBean);
		return variables;
	}

}
